﻿using System;
using System.Collections.Generic;

namespace Simp.CodeModel
{
	/// <summary>
	/// Represents a function, potentially composed of other functions, able to take parameters in and simplify itself,
	/// eventually into a primitive function.  We also call a function a <c>function tree</c> since when a function
	/// is made of sub functions themselves made of sub functions, that also represent a tree.
	/// </summary>
	/// <remarks>
	/// <para>Functions are always immutable:  any manipulation creates new functions (copies).</para>
	/// <para>
	/// Functions use the visitor pattern in order to be altered.  This allow the visitor to ignore the inner structure of
	/// most of the functions in the function tree and visit / alter only the functions it's interested into.
	/// </para>
	/// </remarks>
	public interface IFunction
	{
		/// <summary>Name of the function.</summary>
		string FunctionName { get; }

		/// <summary>Returns the list of parameter names.</summary>
		string[] ParameterNames { get; }

		/// <summary>Returns the default parameter values.</summary>
		IFunctionParameterBinding[] DefaultParameterValues { get; }

		/// <summary>Simplifies the function and return a simplified version.</summary>
		/// <remarks>A simplification typically reduce the number of sub-functions.</remarks>
		/// <param name="simplificationMode"/>
		/// <param name="parameters"/>
		/// <returns>Simplified function.</returns>
		IFunction Simplify(SimplificationMode simplificationMode, params IFunction[] parameters);

		/// <summary>Accepts a visitor.</summary>
		/// <remarks>
		/// The contract of this method is to allow the visitor to visit every sub function and then
		/// rebuild a new version of itself with the visited version of the sub functions.
		/// If the visitor returns <c>null</c> on every sub-functions, the function can return <c>null</c>, this avoids
		/// re-creating identical objects.
		/// </remarks>
		/// <param name="visitor"></param>
		/// <returns></returns>
		IFunction AcceptVisitor(IFunctionVisitor visitor);
	}
}